﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LearnCSharp
{
    /*
        * *************************************************************************************
        * *************************************************************************************
        *                                      FONCTION
        * *************************************************************************************
        * *************************************************************************************
    */
    /// <summary> FonctionCSharp </summary>
    public class FonctionCSharp
    {
        static void Main2(string[] args)
        {
            int[] t = { 10, 20, 30 };
            foreach (int i in t) Console.WriteLine("Tableau : {0}", i);

            f(t);
            foreach (int i in t) Console.WriteLine("Tableau : {0}", i);

            fref(ref t);
            foreach (int i in t) Console.WriteLine("Tableau : {0}", i);

            int[] tout;
            fout(out tout);
            foreach (int i in tout) Console.WriteLine("Tableau : {0}", i);

            Object o1 = new Object();
            Object o2 = new Object();
            Object o3 = new Object();
            fparam(10, o1, o2, o3);

            fdefaut(10, 2.4);

            // Arguments nommés
            int ii2 = 2;
            fnomme(10, d: 2.6, i2: ref ii2);

            //////////////////////////////////////////////////
            Console.ReadLine();
        }

        ////////////////////////////
        // REFERENCE
        // Passage par référence (mais la fonction N A PAS CONNAISSANCE DE LA REFRENCE seulement du contenu du tableau
        static void f(int[] tp)
        {
            // Possibilité de modifier le contenu du taleau
            for (var i = 0; i < tp.Length; i++)
            {
                tp[i]++;
            }

            // Modifier la référence ne seront pas répercuté en dehors de la fonction
            int[] t2 = new int[tp.Length + 1];
            t2[t2.Length - 1] = 666; // on agrandit le tableau
            tp = t2;

            tp = null;

            tp = new int[] { 666 };
        }

        ////////////////////////////
        // REF : Passage par référence avec "ref" (la fonction A CONNAISSANCE DE LA REFERENCE)
        static void fref(ref int[] tp)
        {
            // Possibilité de modifier le contenu du taleau
            for (var i = 0; i < tp.Length; i++)
            {
                tp[i]++;
            }

            // Modifier la référence ne seront pas répercuté en dehors de la fonction
            int[] t2 = new int[tp.Length + 1];
            t2[t2.Length - 1] = 666; // on agrandit le tableau
            tp = t2;

            //tp = null;

            //tp = new int[]{666};
        }

        ////////////////////////////
        // OUT : Passage par référence avec "out" indique qu'on doit impérativement initialiser la variable
        static void fout(out int[] tout)
        {
            tout = new int[2];
            tout[0] = 1;
            tout[1] = 2;
        }

        ////////////////////////////
        // PARAMS : Arguments variable en type et en nombre (forcément en dernier arument)
        static void fparam(int i, params object[] para)
        {
        }

        ////////////////////////////
        // DEFAUT : Argument par défaut (forcément le plus à droite)
        static void fdefaut(int i, double d = 2.2, string s = "test")
        {
        }

        ////////////////////////////
        // NOMME : Argument par défaut (forcément le plus à droite)
        static void fnomme(int i, ref int i2, double d = 2.2, string s = "test", object o2 = null)
        {
        }
    }

    /*
        * *************************************************************************************
        * *************************************************************************************
        *                                      CLASSE
        * *************************************************************************************
        * *************************************************************************************
    */

    /// <summary> ClasseCSharpBase </summary>
    public class ClasseCSharpBase
    {
        ////////////////////////////
        // PROPRIETE :
        int abc { get; set; } //accesseurs

        /// <summary> </summary>
        public ClasseCSharpBase()
        {
            Console.WriteLine("Constructeur base : ClasseCSharpBase()");
        }

        /// <summary> </summary>
        public ClasseCSharpBase(int abc):this()
        {
            this.abc = abc;
            Console.WriteLine("Constructeur base : ClasseCSharpBase(int abc)");
        }
    }
    /// <summary> ClasseCSharp </summary>
    public class ClasseCSharp : ClasseCSharpBase,IDisposable,ICloneable
    {
        static void Main2(string[] args)
        {
            int i = 1, j = 2;
            ClasseCSharp C1 = new ClasseCSharp(i, j);
            using(C1)
            {
                // ...
            }// Apelle automatiquement la fonction Dispose à la fin de la fonction
        }

        ////////////////////////////
        // VOCABULAIRE :
        // Variables, champs ou attributs
        // Fonctions, méthodes
        // Propriétés
        // Indexeurs

        ////////////////////////////
        // PROTECTION : private, protected, public, internal
                    int a; // = private
        private     int b;
        /// <summary></summary>
        protected   int c;
        /// <summary></summary>
        public      int d;
        
        internal    int z; // portée dans le même assemblage


        ////////////////////////////
        // CONST : affectation de la valeur seulement à la déclaration de la variable
        const double PI = 3.14;

        ////////////////////////////
        // READONLY : affectation de la valeur seulement dans le constructeur
        readonly double PI2;

        ////////////////////////////
        // CONSTRUCTEURS    
        /// <summary> ClasseCSharp </summary>
        public ClasseCSharp()
        {
            // Contructeur de ClasseCSharpBase d'abord appelé

            PI2 = 3.14;
            PI2++;

            a++; b++; c++; d++; z++;

            Console.WriteLine("Constructeur : ClasseCSharp()");
        }

        ////////////////////////////
        // BASE : appel constructeur de la classe de base
        /// <summary> </summary>
        public ClasseCSharp( int i):base(i)
        {
            // Contructeur de ClasseCSharpBase d'abord appelé

            Console.WriteLine("Constructeur : ClasseCSharp(int i)");
        }
        int j;
        /// <summary> </summary>
        ////////////////////////////
        // THIS(i) : appel constructeur ayant un argument
        public ClasseCSharp(int i, int j):this(i)
        {
            // Contructeur de ClasseCSharpBase d'abord appelé
            
            this.j = j;
            Console.WriteLine("Constructeur : ClasseCSharp(int i, int j)");
        }

        ////////////////////////////
        // SURCHARGE : seulement différentiable par le nombre et le type des arguments
        void TestFct123(int i) { }
        void TestFct123(int i,int j) { }
        void TestFct123(double i) { }

        ////////////////////////////
        // DISPOSE : fait office de destructeur, Mettre la classe dérivant de l'interface IDisposable
        /// <summary> Dispose </summary>
        public void Dispose() { Console.WriteLine("Dispose est appelé à la fin du bloc using");  }
        
        ////////////////////////////
        // CLONE : Mettre la classe dérivant de l'interface ICloneable
        /// <summary> </summary>
        public Object Clone()
        {
            ClasseCSharp c = (ClasseCSharp)MemberwiseClone(); // Copie des variables 
            //if (OtherObject != null) c.OtherObject = (ClasseCSharp)OtherObject.Clone();
            return c;
        }

        /// <summary> </summary>
        public void CopyTo( ClasseCSharp c)
        {
            c = (ClasseCSharp)Clone();
        }

        ////////////////////////////
        // EQUALS , OPERATOR ==, !=
        /// <summary> </summary>
        public override bool Equals(object o)
        {
            ClasseCSharp c = (ClasseCSharp)o;
            return this.j == c.j;
        }

        /// <summary> </summary>
        public static bool operator ==(ClasseCSharp a, ClasseCSharp b)
        {
            return a.Equals(b);
        }

        /// <summary> </summary>
        public static bool operator !=(ClasseCSharp a, ClasseCSharp b)
        {
            return !a.Equals(b);
        }

        ////////////////////////////
        // GETHASHCODE 
        /// <summary> </summary>
        public override int GetHashCode()
        {
            return this.ToString().GetHashCode();
        }

        ////////////////////////////
        // OPERATEUR CONVERSION
        /// <summary> </summary>
        public static implicit operator int(ClasseCSharp c)
        {
            return c.j;
        }
    }

    ///////////////////////////
    // SEALED : classe non dérivée
    sealed class ClasseNonDerivee
    {
    }
    
    ////////////////////////////
    // EXTENSION SUP_ : Permet d'ajouter des fonctions à des fonctions dont on dispose pas du code
    static class SupDateTime
    {
        public static bool Anterieur(this DateTime d)
        {
            return d < DateTime.Now;
        }

    }

	/*
	   * *************************************************************************************
	   * *************************************************************************************
	   *                                      CLASSE MODELE
	   * *************************************************************************************
	   * *************************************************************************************
   */

	/// <summary>
	/// 
	/// </summary>
	namespace ModelNamespace
	{
		/// <summary>
		/// 
		/// </summary>
		class ModelClass
		{

		#region Attributs & Properties
			
			private string	_strName;
			public string	Name{get;set;}

		#endregion
		#region Constructors

			public ModelClass()
			{
				_strName = "";
			}			

		#endregion
		#region Indexers
		#endregion
		#region Operators

			public override bool Equals(object oValue)
			{
				return Name.ToString() == oValue.ToString();
			}

			public static bool operator ==(ModelClass oCase, string strValue)
			{
				return oCase.Equals(strValue);
			}

			public static bool operator !=(ModelClass oCase, string strValue)
			{
				return !oCase.Equals(strValue);
			}

			public static implicit operator string(ModelClass oCase)
			{
				return oCase.Name.ToString();
			}

			public override int GetHashCode()
			{
				return base.GetHashCode();
			}

		#endregion
		#region Methods

			public override string ToString()
			{
				return _strName;
			}

			public object Clone()
			{
				return new object();
			}
		#endregion

		}
	}

}
